package com.josework.springhelloworld.utils.forkjoin;

import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

public class ForkJoinSumCalculator extends RecursiveTask<Long> {

    private final long[] numbers;
    private final int start;
    private final int end;

    public static final long THRESHOLD = 10_000;

    /**
     * 公共构造函数用于创建主任务
     * @param numbers
     */
    public ForkJoinSumCalculator(long[] numbers) {
        this(numbers,0,numbers.length);
    }

    /**
     * 私有构造函数用于以递归方式为主任务创建子任务。
     * @param numbers
     * @param start
     * @param end
     */
    private ForkJoinSumCalculator(long[] numbers, int start, int end) {
        this.numbers = numbers;
        this.start = start;
        this.end = end;
    }

    /**
     *该任务负责求和的部分的大小
     * @return
     */
    @Override
    protected Long compute() {
        int length = end - start;
        if (length<=THRESHOLD){
            /**
             * 如果大小小于或等于阈值，顺序计算结果
             */
            return computeSequentially();
        }
        //创建一个子任务来为数组的前一半求和。
        ForkJoinSumCalculator leftTask =
                new ForkJoinSumCalculator(numbers,start,start+length/2);
        //利用另一个ForkJoinPool线程异步执行新创建的子任务。
        leftTask.fork();
        //创建一个任务为数组的后一半求和。
        ForkJoinSumCalculator rightTask =
                new ForkJoinSumCalculator(numbers,start+length/2,end);
        //同步执行第二个子任务，有可能允许进一步递归划分。
        Long rightResult = rightTask.compute();
        //读取第一个子任务的结果，如果尚未完成就等待。
        Long leftResult = leftTask.join();
        //该任务的结果是两个子任务结果的组合
        return leftResult+rightResult;
    }

    /**
     * 在子任务不再可分时计算结果的简单算法。
     * @return
     */
    private long computeSequentially(){
        long sum = 0;
        for (int i = 0; i < end; i++) {
            sum+= numbers[i];
        }
        return sum;
    }

    public static long forkJoinSum(long n){
        long[] numbers = LongStream.rangeClosed(1,n).toArray();
        ForkJoinTask<Long> task = new ForkJoinSumCalculator(numbers);
        return new ForkJoinPool().invoke(task);
    }

    public static int countWords(String s){
        int counter = 0;
        //前一个字符是空格，而当前遍历的字符不是空格时候,将单词计数器加一
        boolean lastSpace = true;
        for (char c : s.toCharArray()) {
            if (Character.isWhitespace(c)){
                lastSpace = true;
            } else {
                if (lastSpace) counter++;
                lastSpace =false;
            }
        }
        return counter;
    }



    public static void main(String[] args) {
        final String SENTENCE =
                " Nel mezzo del cammin di nostra vita " +
                        "mi ritrovai in una selva oscura" +
                        " ché la dritta via era smarrita ";
        System.out.println("Found " + countWords(SENTENCE) + " words");

        //Found 19 words
        Stream<Character> stream = IntStream.range(0, SENTENCE.length())
                .mapToObj(SENTENCE::charAt);

        //Found 19 words
//        System.out.println("Found " +
//                WordCounter.countWords(stream) + " words");

        //换成并行流会出问题 Found 40 words
        System.out.println("Found " +
                WordCounter.countWords(stream) + " words");

        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello,world");
            }
        };
        r1.run();

        int a = 10;
        Runnable r2 = () -> {
//            int a = 10;
            System.out.println(a);
        };
        r2.run();

        Stream<String> stringStream = Stream.of("hello","hello", "world", "hello,world");

        Set<String> set = stringStream
                .collect(Collectors.toCollection(TreeSet::new));
        set.forEach(System.out::println);



    }




}
